package com.dmj.sqldsl.executor.transaction;

import com.dmj.sqldsl.executor.exception.ExecutionException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
@Getter
public class Transaction {

  private final TransactionDefinition definition;

  private final List<DefaultTransactionStatus> statuses;

  private TransactionConnection connection;

  public static Transaction create(TransactionDefinition definition,
      DefaultTransactionStatus status) {
    List<DefaultTransactionStatus> statuses = new ArrayList<>();
    statuses.add(status);
    return new Transaction(definition, statuses);
  }

  @SuppressWarnings("SuspiciousMethodCalls")
  public void remove(TransactionStatus status) {
    statuses.remove(status);
  }

  public void rollback() throws SQLException {
    statuses.forEach(status -> status.setCompleted(true));
    connection.rollback();
  }

  public void commit() throws SQLException {
    statuses.forEach(status -> status.setCompleted(true));
    connection.commit();
  }

  public void release() {
    try {
      connection.release();
    } catch (SQLException e) {
      throw new TransactionException(e);
    }
  }

  protected Connection getTransactionConnection(Supplier<Connection> getConnectionFunction) {
    if (Objects.nonNull(this.connection)) {
      return this.connection;
    }
    try {
      Connection connection = getConnectionFunction.get();
      this.connection = TransactionConnection.of(definition.getIsolation(), connection);
      return this.connection;
    } catch (SQLException e) {
      throw new ExecutionException(e);
    }
  }
}
